package org.chen.ly.scheduler;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.chen.common.lytrip.crawler.CrawlerExecutionResult;
import org.chen.common.lytrip.crawler.CrawlerTask;
import org.chen.common.lytrip.crawler.CrawlerTaskLog;
import org.chen.ly.service.CrawlerTaskLogService;
import org.chen.ly.service.CrawlerTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

@Slf4j
@Component
public class CrawlerScheduler implements ApplicationRunner {

    // 内存中的调度任务引用
    private final Map<String, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();

    @Autowired
    private CrawlerTaskService crawlerTaskService;

    @Autowired
    private CrawlerTaskLogService crawlerTaskLogService;

    @Autowired
    private TaskScheduler taskScheduler;

    /**
     * 系统关闭时停止所有任务
     */
    @PreDestroy
    public void shutdown() {
        log.info("系统关闭，停止所有定时任务...");

        // 取消所有调度任务
        scheduledFutures.values().forEach(future -> {
            if (future != null && !future.isCancelled()) {
                future.cancel(false);
            }
        });
        scheduledFutures.clear();

        // 更新数据库中活跃任务的状态
        crawlerTaskService.stopAllActiveTasks();

        log.info("所有定时任务已停止");
    }

    /**
     * 系统启动时自动恢复任务
     */
    @Override
    public void run(ApplicationArguments args) {
        log.info("系统启动，开始恢复定时任务...");

        List<CrawlerTask> activeTasks = crawlerTaskService.getActiveTasks();

        for (CrawlerTask taskEntity : activeTasks) {
            try {
                CrawlerTask task = taskEntity.toScheduledTask();

                if (task.getStatus() == 1) { // 1表示启用状态
                    // 重新创建调度任务
                    ScheduledFuture<?> future = taskScheduler.schedule(
                            () -> executeScheduledTask(task.getId()),
                            new CronTrigger(task.getCronExpression())
                    );
                    scheduledFutures.put(String.valueOf(task.getId()), future);

                    log.info("恢复活跃任务: {} - {}", task.getTaskName(), task.getCronExpression());
                } else if (task.getStatus() == 0) { // 0表示暂停状态
                    log.info("发现暂停任务: {} - 保持暂停状态", task.getTaskName());
                }

            } catch (Exception e) {
                log.error("恢复任务失败: {}", taskEntity.getTaskName(), e);
            }
        }

        log.info("定时任务恢复完成，共恢复 {} 个任务", scheduledFutures.size());
    }

    /**
     * 添加新的定时任务
     */
    public void addScheduledTask(CrawlerTask task) {
        try {
            crawlerTaskService.save(task);

            ScheduledFuture<?> future = taskScheduler.schedule(
                    () -> executeScheduledTask(task.getId()),
                    new CronTrigger(task.getCronExpression())
            );
            scheduledFutures.put(String.valueOf(task.getId()), future);
            log.info("创建定时任务: {} - {}", task.getTaskName(), task.getCronExpression());
        } catch (Exception e) {
            log.error("创建定时任务失败: {}", task.getTaskName(), e);
            throw new RuntimeException("创建定时任务失败: " + e.getMessage());
        }
    }

    /**
     * 获取定时任务列表
     */
    public List<CrawlerTask> getScheduledTasks() {
        List<CrawlerTask> entities = crawlerTaskService.list(new QueryWrapper<>());
        return entities.stream()
                .map(CrawlerTask::toScheduledTask)
                .collect(Collectors.toList());
    }

    /**
     * 执行定时任务
     */
    private void executeScheduledTask(Long taskId) {
        // 从数据库获取最新的任务信息
        CrawlerTask taskEntity = crawlerTaskService.getById(taskId);
        if (taskEntity == null) {
            log.warn("任务不存在: {}", taskId);
            return;
        }

        CrawlerTask task = taskEntity.toScheduledTask();

        if (task.getStatus() != 1) { // 1表示启用状态
            log.info("任务不是活跃状态，跳过执行: {} - {}", task.getTaskName(), task.getStatus());
            return;
        }

        long startTime = System.currentTimeMillis();
        CrawlerExecutionResult result = new CrawlerExecutionResult();
        result.setTaskId(String.valueOf(task.getId()));
        result.setTaskName(task.getTaskName());
        result.setKeywords(task.getKeywords());
        result.setStartPageIndex(task.getStartPageIndex());
        result.setEndPageIndex(task.getEndPageIndex());
        result.setPageSize(task.getPageSize());
        result.setExecuteTime(LocalDateTime.now());
        result.setDepartureCity(task.getDepartureCity());

        try {
            log.info("开始执行定时任务: {}", task.getTaskName());

            // 执行任务逻辑并获取执行结果
            CrawlerExecutionResult executionResult = crawlerTaskService.executeTaskWithResult(task.getId());

            // 合并执行结果
            result.setSuccess(true);
            result.setProductCount(executionResult.getProductCount());
            result.setNewProductCount(executionResult.getNewProductCount());
            result.setUpdateProductCount(executionResult.getUpdateProductCount());
            result.setExecutionDetail(executionResult.getExecutionDetail());

            // 更新任务统计
            task.setLastRunTime(LocalDateTime.now());
            task.setTotalRuns(task.getTotalRuns() + 1);
            task.setSuccessRuns(task.getSuccessRuns() + 1);
            task.setLastRunResult("SUCCESS");
            task.setExecutionSummary(String.format("抓取%d个商品，新增%d个，更新%d个",
                    result.getProductCount(), result.getNewProductCount(), result.getUpdateProductCount()));

            log.info("定时任务执行成功: {} - {}", task.getTaskName(), task.getExecutionSummary());

        } catch (Exception e) {
            log.error("执行定时任务失败: {}", task.getTaskName(), e);

            task.setLastRunTime(LocalDateTime.now());
            task.setTotalRuns(task.getTotalRuns() + 1);
            task.setFailRuns(task.getFailRuns() + 1);
            task.setLastRunResult("FAILED");
            task.setLastErrorMessage(e.getMessage());
            task.setExecutionSummary("执行失败: " + e.getMessage());

            result.setSuccess(false);
            result.setErrorMessage(e.getMessage());
            result.setExecutionDetail("任务执行异常: " + e.getMessage());

        } finally {
            result.setTotalDuration(System.currentTimeMillis() - startTime);

            // 更新数据库统计
            updateTaskExecutionStats(task);

            // 保存执行日志
            saveExecutionLog(result);
        }
    }

    /**
     * 更新任务执行统计
     */
    private void updateTaskExecutionStats(CrawlerTask task) {
        try {
            // 计算下次执行时间
            task.setNextRunTime(crawlerTaskService.calculateNextRunTime(task.getCronExpression()));
            task.setUpdateTime(LocalDateTime.now());

            // 更新数据库
            crawlerTaskService.updateById(task);

            log.debug("更新任务统计完成: {} - 总运行:{}, 成功:{}, 失败:{}, 成功率:{}%",
                    task.getTaskName(), task.getTotalRuns(), task.getSuccessRuns(),
                    task.getFailRuns(), task.getSuccessRate());

        } catch (Exception e) {
            log.error("更新任务统计失败: {}", task.getTaskName(), e);
        }
    }

    /**
     * 保存执行日志
     */
    private void saveExecutionLog(CrawlerExecutionResult result) {
        try {
            CrawlerTaskLog taskLog = new CrawlerTaskLog();
            taskLog.setTaskId(Long.valueOf(result.getTaskId()));
            taskLog.setTaskName(result.getTaskName());
            taskLog.setKeywords(result.getKeywords());
            taskLog.setStartPageIndex(result.getStartPageIndex());
            taskLog.setEndPageIndex(result.getEndPageIndex());
            taskLog.setTotalPages(result.getTotalPages());
            taskLog.setFailedPages(result.getFailedPages());
            taskLog.setSuccessPages(result.getSuccessPages());
            taskLog.setPageSize(result.getPageSize());
            taskLog.setStartTime(result.getExecuteTime());
            taskLog.setEndTime(result.getExecuteTime().plusNanos(result.getTotalDuration() * 1_000_000));
            taskLog.setDuration(result.getTotalDuration());
            taskLog.setStatus(result.isSuccess() ? 1 : 0);
            taskLog.setProductCount(result.getProductCount());
            taskLog.setNewProductCount(result.getNewProductCount());
            taskLog.setUpdateProductCount(result.getUpdateProductCount());
            taskLog.setErrorMessage(result.getErrorMessage());
            taskLog.setExecutionDetail(result.getExecutionDetail());
            taskLog.setCreateTime(LocalDateTime.now());

            crawlerTaskLogService.save(taskLog);

            log.debug("保存执行日志完成: {} - 耗时:{}ms, 状态:{}",
                    result.getTaskName(), result.getTotalDuration(),
                    result.isSuccess() ? "成功" : "失败");

        } catch (Exception e) {
            log.error("保存执行日志失败: {}", result.getTaskName(), e);
        }
    }

    public CrawlerTask updateScheduledTask(CrawlerTask task) {
        try {
            // 1. 检查任务是否存在
            CrawlerTask existingTask = crawlerTaskService.getById(task.getId());
            if (existingTask == null) {
                throw new RuntimeException("任务不存在: " + task.getId());
            }

            // 2. 取消现有的调度任务
            ScheduledFuture<?> existingFuture = scheduledFutures.remove(String.valueOf(task.getId()));
            if (existingFuture != null) {
                existingFuture.cancel(false);
                log.info("取消现有调度任务: {}", existingTask.getTaskName());
            }

            // 3. 更新任务信息
            CrawlerTask updatedTask = new CrawlerTask();

            // 保持不变的字段
            updatedTask.setId(existingTask.getId());
            updatedTask.setCreateTime(existingTask.getCreateTime());
            updatedTask.setTotalRuns(existingTask.getTotalRuns());
            updatedTask.setSuccessRuns(existingTask.getSuccessRuns());
            updatedTask.setFailRuns(existingTask.getFailRuns());
            updatedTask.setLastRunTime(existingTask.getLastRunTime());
            updatedTask.setLastRunResult(existingTask.getLastRunResult());
            updatedTask.setLastErrorMessage(existingTask.getLastErrorMessage());
            updatedTask.setExecutionSummary(existingTask.getExecutionSummary());
            updatedTask.setStartPageIndex(task.getStartPageIndex());
            updatedTask.setEndPageIndex(task.getEndPageIndex());
            updatedTask.setPageSize(task.getPageSize());
            updatedTask.setKeywords(task.getKeywords());
            updatedTask.setDays(task.getDays());
            updatedTask.setCronExpression(task.getCronExpression());
            updatedTask.setDescription(task.getDescription());

            // 可修改的字段
            updatedTask.setTaskName(task.getTaskName());
            updatedTask.setStatus(1); // 更新后重新激活

            // 调度和导出配置
            updatedTask.setCronExpression(task.getCronExpression());

            crawlerTaskService.updateById(updatedTask);

            // 5. 重新创建调度任务（如果任务处于活跃状态）
            if (updatedTask.getStatus() == 1) { // 1表示启用状态
                ScheduledFuture<?> newFuture = taskScheduler.schedule(
                        () -> executeScheduledTask(updatedTask.getId()),
                        new CronTrigger(updatedTask.getCronExpression())
                );
                scheduledFutures.put(String.valueOf(updatedTask.getId()), newFuture);
            }

            log.info("更新定时任务成功: {} - 新的Cron: {}",
                    updatedTask.getTaskName(), updatedTask.getCronExpression());

            return updatedTask;

        } catch (Exception e) {
            log.error("更新定时任务失败: {}", task.getId(), e);
            throw new RuntimeException("更新定时任务失败: " + e.getMessage());
        }
    }

    public void deleteScheduledTask(Long id) {
        try {
            // 取消调度任务
            ScheduledFuture<?> future = scheduledFutures.remove(String.valueOf(id));
            if (future != null) {
                future.cancel(false);
            }

            // 从数据库删除
            crawlerTaskService.removeById(id);

            log.info("删除定时任务: {}", id);

        } catch (Exception e) {
            log.error("删除定时任务失败: {}", id, e);
            throw new RuntimeException("删除定时任务失败: " + e.getMessage());
        }
    }

    public void toggleScheduledTask(Long taskId, String action) {
        try {
            CrawlerTask taskEntity = crawlerTaskService.getById(taskId);
            if (taskEntity == null) {
                throw new RuntimeException("任务不存在: " + taskId);
            }

            if ("pause".equals(action)) {
                // 暂停任务
                ScheduledFuture<?> future = scheduledFutures.remove(String.valueOf(taskId));
                if (future != null) {
                    future.cancel(false);
                }
                crawlerTaskService.updateStatus(taskId, 0); // 0表示暂停状态

            } else if ("resume".equals(action)) {
                // 恢复任务
                CrawlerTask task = taskEntity.toScheduledTask();
                ScheduledFuture<?> future = taskScheduler.schedule(
                        () -> executeScheduledTask(taskId),
                        new CronTrigger(task.getCronExpression())
                );
                scheduledFutures.put(String.valueOf(taskId), future);
                crawlerTaskService.updateStatus(taskId, 1); // 1表示启用状态
            }

        } catch (Exception e) {
            log.error("切换任务状态失败: {} - {}", taskId, action, e);
            throw new RuntimeException("切换任务状态失败: " + e.getMessage());
        }
    }

    /**
     * 立即执行
     * @param id 任务ID
     */
    public void executeScheduledTaskNow(Long id) {
        // 在新线程中异步执行
        new Thread(() -> executeScheduledTask(id)).start();
    }

    public List<CrawlerTaskLog> getTaskLogs(Long taskId, int limit) {
        return crawlerTaskLogService.findByTaskId(taskId, limit);
    }
}
